package user;

import static org.junit.Assert.*;

import java.util.*;

import msg.*;

import org.junit.*;

import registration.RegistrationManager;

import common.*;
import common.dal.Transaction;
import common.exceptions.*;
import common.interfaces.IPersistent;

@SuppressWarnings({"static-method", "javadoc"})
public class LoginManagerTest extends DBTest {
	private static LoginManager	$;
	
	@Override
	protected IPersistent setPersistent(Transaction t) {
		$ = LoginManager.getNewInstance(t);
		return $;
	}
	
	@Override
	protected IPersistent getPersistent() {
		return $;
	}
	
	@BeforeClass
	public static void setupBeforeClass() throws Exception {
		DALTests.setupBeforeClass();
		t = new Transaction();
		$ = LoginManager.getNewInstance(t);
		RegistrationManager.getNewInstance(t).clear();
		MessageManager.getNewInstance(t).clear();
		t.commit();
	}
	
	@After
	@Before
	public void clean() throws Exception {
		$.clear();
	}
	
	@Test(expected = WrongPasswordException.class)
	public void testLogUserNoneExistingUser() throws Exception {
		$.loginUser("user", "pass");
	}
	
	@Test(expected = WrongPasswordException.class)
	public void testLogUserWrongPassword() throws Exception {
		$.registerUser("user", "gal", "pass");
		$.loginUser("user", "passpass");
	}
	
	@Test
	public void testLogUser() throws Exception {
		$.registerUser("user", "gal", "pass");
		$.registerUser("user2", "gal", "pass");
		assertEquals((long)$.loginUser("user", "pass").getId(), 0);
		assertEquals((long)$.loginUser("user", "pass").getId(), 1);
		assertEquals((long)$.loginUser("user2", "pass").getId(), 2);
		assertEquals((long)$.loginUser("user", "pass").getId(), 3);
		assertEquals((long)$.loginUser("user2", "pass").getId(), 4);
	}
	
	@Test
	public void testLogoutUserNotLoggedIn() throws Exception {
		assertFalse($.logoutUser(0));
	}
	
	@Test
	public void testLogoutUser() throws Exception {
		$.registerUser("user", "gal", "pass");
		Session session = $.loginUser("user", "pass");
		assertTrue($.logoutUser(session.getId()));
	}
	
	@Test(expected = InvalidKeyException.class)
	public void testLogoutUserInvalidatingSession() throws Exception {
		$.registerUser("user", "gal", "pass");
		Session session = $.loginUser("user", "pass");
		assertTrue($.logoutUser(session.getId()));
		$.loginUser("user", "pass");
		$.getSession(session.getId());
	}
	
	@Test
	public void testRegisterUser() throws Exception {
		$.registerUser("user", "gal", "pass");
	}
	
	@Test(expected = ExistingEntityException.class)
	public void testRegisterUserExisting() throws Exception {
		$.registerUser("user", "gal", "pass");
		$.registerUser("user", "gal", "pass");
	}
	
	// @Test(expected = WrongAdminPasswordException.class)
	// public void testRegisterAdministratorWrongPass() throws Exception {
	// $.registerAdmin("user", "Admin", "pass", "rosebud" + "!");
	// }
	
	// @Test(expected = ExistingEntityException.class)
	// public void testRegisterAdministratorExistingUser() throws Exception {
	// $.registerUser("user", "gal", "pass");
	// $.registerAdmin("user", "Admin", "pass", "rosebud");
	// }
	
	// @Test
	// public void testRegisterAdministrator() throws Exception {
	// Administrator admin = $.registerAdmin("user", "Admin", "pass", "rosebud");
	// assertEquals(admin, $.get("user"));
	// }
	
	@Test
	public void testDeleteUser() throws Exception {
		assertFalse($.deleteUser("user", "pass"));
		$.registerUser("user", "gal", "pass");
		assertTrue($.deleteUser("user", "pass"));
	}
	
	@Test(expected = InvalidKeyException.class)
	public void testDeleteUserCheckSessions() throws Exception {
		$.registerUser("user", "gal", "pass");
		Session session = $.loginUser("user", "pass");
		$.deleteUser("user", "pass");
		$.getSession(session.getId());
	}
	
	@Test(expected = IllegalStateException.class)
	public void testDeleteUserExistingEvents() throws Exception {
		try {
			User user = $.registerUser("user", "gal", "pass");
			EventMessage event = MessageManager.getNewInstance(t)
					.createNewEventMessage(new Location(0, 0), "", user, getTomorrow(), 1);
			RegistrationManager.getNewInstance(t).registerUserForEvent(user, event);
			$.deleteUser(user.getLogin(), "pass");
		} finally {
			RegistrationManager.getNewInstance(t).clear();
			MessageManager.getNewInstance(t).clear();
		}
	}
	
	// @Test(expected = InvalidUserException.class)
	// public void testDeleteUserWithAdministratorBadAdmin() throws Exception {
	// Administrator admin = new Administrator("bla", "bla bla");
	// $.registerUser("user", "gal", "pass");
	// $.deleteUser("user", admin);
	// }
	
	// @Test(expected = InvalidUserException.class)
	// public void testDeleteUserWithAdministratorAdminAsUser() throws Exception {
	// Administrator admin = new Administrator("bla", "bla bla");
	// $.registerUser(admin.getLogin(), admin.getName(), "no one cares");
	// $.registerUser("user", "gal", "pass");
	// $.deleteUser("user", admin);
	// }
	
	// @Test
	// public void testDeleteUserWithAdministrator() throws Exception {
	// Administrator admin = $.registerAdmin("mr_admin", "gal", "whatever", "rosebud");
	// assertFalse($.deleteUser("user", admin));
	// $.registerUser("user", "gal", "pass");
	// assertTrue($.deleteUser("user", admin));
	// }
	
	// @Test
	// public void testCheckAdminPassword() throws Exception {
	// assertFalse($.checkAdminPassword("rosebud" + "!"));
	// assertTrue($.checkAdminPassword("rosebud"));
	// }
	
	@Test
	public void testDelete() throws Exception {
		assertFalse($.deleteUser(getFakeUser().getLogin(), "whatever"));
		$.registerUser("gal", "gal", "pass");
		assertTrue($.deleteUser("gal", "pass"));
		assertFalse($.deleteUser("gal", "pass"));
	}
	
	@Test
	public void testGetAll() throws Exception {
		Set<User> expected = new HashSet<>();
		
		for (int i = 0; i < 10; i++) {
			expected.add($.registerUser("login" + i, "", ""));
		}
		
		assertEquals(expected, new HashSet<>($.getAll()));
	}
	
	@Test(expected = InvalidKeyException.class)
	public void testGetSessionInvalid() throws Exception {
		$.getSession(12);
	}
	
	@Test
	public void testGetSession() throws Exception {
		User user = $.registerUser("gal", "gal", "pass");
		Session session = $.loginUser(user.getLogin(), "pass");
		assertEquals(session, $.getSession(session.getId()));
	}
	
	@Test
	public void testDifferentIdsDifferentSession() throws Exception {
		User user = $.registerUser("a" + new Date().getTime(), "gal", PASSWORD);
		long id1 = $.loginUser(user.getId(), PASSWORD).getId();
		t.commit();
		t = new Transaction();
		$ = LoginManager.getNewInstance(t);
		long id2 = $.loginUser(user.getId(), PASSWORD).getId();
		assertEquals(id2, id1 + 1);
		t.commit();
		t = new Transaction();
		$ = LoginManager.getNewInstance(t);
		long id3 = $.loginUser(user.getId(), PASSWORD).getId();
		assertEquals(id3, id2 + 1);
	}
}
